package find.prj.lib;

import java.util.Collection;
import java.util.Iterator;

public abstract class ListBase<T> implements Collection<T> {

	protected int Size;
	
	public int size() {
		return this.Size;
	}
		
	protected abstract ListNode<T> getListNode(int index) ;
	
	public T get(int index) {
		if ((index < this.Size) && (index >= 0)) {
			ListNode<T> node = this.getListNode(index);
			return node.getValue();
		}
		else
			throw new IndexOutOfBoundsException();
	}

	public abstract boolean add(T value);
	
	public void set(int index, T value) {
		if ((index < this.Size) && (index >= 0)) {
			ListNode<T> node = this.getListNode(index);
			node.setValue(value);
		}
		else
			throw new IndexOutOfBoundsException();
	}

	public boolean addAll(Collection<? extends T> arg0) {
		if (! arg0.isEmpty()) {
			for (T value : arg0)
				this.add(value);
				return true;
		}
			return false;
	}

	public abstract void removeIndex(int index);

	public boolean remove(Object arg0) {
		boolean result = false;
		for (int i=0; i < this.Size; ) {
			T value = this.get(i);
			if ((arg0 == null && value == null) || value.equals(arg0)) {
				removeIndex(i);
				result = true;
			}
			else
				i++;
		}
		return result;
	}

	public boolean removeAll(Collection<?> arg0) {
		boolean result = false;
		if (! arg0.isEmpty())
			for (Object arg0Value : arg0) {
				this.remove(arg0Value);
				result = true;
		}	
		return result;
	}

	public boolean isEmpty() {
		if (Size == 0)
			return true;
		return false;
	}
		
	public String toString() {
		StringBuilder result = new StringBuilder("");
		if(!this.isEmpty()) {
			for (T value : this)
				if (value == null)
					result.append("null ");
				else
					result.append(value.toString()+" ");
			result.replace(result.length()-1, result.length()-1, "");
		}
		return new String(result);
	}

	public Iterator<T> iterator() {
		Iterator<T> iter = new Iterator<T>() {
			private int Iteration = 0;
			
			@Override
			public boolean hasNext() {
			if ((this.Iteration < Size) && (getListNode(this.Iteration) != null))
				return true;
				return false;
			}

			@Override
			public T next() {
				T value = get(this.Iteration);
				this.Iteration++;
				return value;
			}
				// Method not supported
			@Override
			public void remove() {
				throw new UnsupportedOperationException();
			}
				
		} ;
		return iter;
	}

	public boolean contains(Object arg0) {
		for (T value : this)
			if ( (value == null && arg0 == null) || value.equals(arg0) )                      
				return true;
		return false;
	}

	public boolean containsAll(Collection<?> arg0) {
		for (Object arg0Value : arg0)
			if (! this.contains(arg0Value))
				return false;
		return true;
	}

	public boolean retainAll(Collection<?> arg0) {
		boolean result = false;
		for (Object arg0Value : arg0)
			if (! this.contains(arg0Value)) {
				result = this.remove(arg0Value);
			}
		return result;
	}

	public Object[] toArray() {
		Object[] array = new Object[this.Size];
		for (int i =0; i < this.Size; i++)
			array[i] = this.get(i);
		return array;
	}

	@SuppressWarnings({ "unchecked", "hiding" })
	public <T> T[] toArray(T[] arg0) {
		if (arg0.length >= this.Size) {
			for (int i =0; i < this.Size; i++)
				arg0[i] = (T) this.get(i);
			return null;
		}
		else
			return (T[])this.toArray();
	}
		
	//Overrides from Object
	@SuppressWarnings("unchecked")
	@Override
	public Object clone() {
		MegaList<T> clonedList = null;
		try {
			clonedList = (MegaList<T>)super.clone();
			clonedList.clear();
			clonedList.addAll(this);
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return clonedList;
	}

}	